import { game } from 'cc';
import { native } from 'cc';
import { dm } from '../../scripts/managers/DataManager';
import { bam } from '../../scripts/managers/BundleAssetsManager';
import { am } from '../../scripts/managers/AudioManager';
import { rxccconfig } from '../../scripts/libs/rxjs/cc3/RxCCConfig';
import { gm } from '../../scripts/managers/GameManager';
import { BaseView } from '../../scripts/libs/rxjs/cc3/BaseView';
import { _decorator, Camera, Node } from 'cc';
import { loadBundle } from '../../scripts/libs/rxjs/cc3/AssetManagerLoad';
import { delay, lastValueFrom } from 'rxjs';
import { udm } from '../../scripts/managers/UserDataManager';
import { nullifySubscription } from '../../scripts/libs/rxjs/utils';
import { linear } from '../../scripts/libs/utils/math';
import { IntervalStartNow, Timer } from '../../scripts/libs/rxjs/cc3/CreatorSchedule';
import { lm } from './LobbyManager';
import { FlowStatus } from './Enums';
import { GameAssetsRefs } from './GameAssetsRefs/GameAssetsRefs';
import { ResType, rm } from '../../scripts/managers/ResourceManager';
import { GameKey } from '../../scripts/managers/SubgameConfig';
import { HotUpdateManager, hum } from '../../scripts/managers/HotUpdateManager';
import { DialogPanel } from './ui/DialogPanel/DialogPanel';
import { i18n } from '../../scripts/i18n';
import { LoadingPanelMode } from '../../scripts/managers/Enums';
import { uim } from '../../scripts/libs/ui/UIManager';
import { Vec2 } from 'cc';
import { Vec3 } from 'cc';
import { v3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('LobbySceneCanvas')
export class LobbySceneCanvas extends BaseView {

    @property(Camera)
    camera: Camera = null;

    @property(Node)
    gameRoot: Node = null;

    public get curProgressValue() { return gm.curProgressValue.value }
    public set curProgressValue(v: number) { gm.curProgressValue.value = v; }
    public get maxProgressValue(): number { return gm.maxProgressValue; }

    onLoadView() {
        this.log('onLoadView');
        lm.lobbySceneCanvas = this;
    }

    onDestroyView() {
        nullifySubscription.call(this, '_bg_sub');
    }

    useObserves() {
        return [
            uim.standby.subscribe(_ => this.log('@@uim.standby', _)),
        ];
    }

    async start() {

        let subInterval = IntervalStartNow(.02, this.node).subscribe(_ => {
            gm.curProgressValue2.value += 1.2;
        });

        this.curProgressValue = 0;
        lm.loadingAssets.value = true;

        this.curProgressValue = 10;

        let mRate = 0;
        let gameAssetsNode = await lastValueFrom(bam.loadGameAssetsRefs('ab_lobby', 'Prefabs/GameAssetsRefs', this.node.parent, (...args: number[]) => {
            let [cur, total] = args;
            mRate = Math.max(mRate, cur / total);
            this.curProgressValue = linear(0, 1, 10, 30, mRate);
        }));
        lm.gameAssetsRefs = gameAssetsNode.getComponent(GameAssetsRefs);

        this.curProgressValue = 30;
        await lastValueFrom(bam.loadXlsx('ab_lobby', 'Config/Xlsx'));
        dm.initXlsx();

        udm.initialize();

        this.curProgressValue = 100;

        lm.frontTipEnabled.value = true;

        subInterval.unsubscribe();

        // wsm.connect();

        lm.loadingAssets.value = false;

        await lastValueFrom(lm.loadingEnabled.whenFalseOnce());
        await lastValueFrom(lm.frontTipReady.whenTrueOnce());
        this.checkHotUpdate();

        this.log('canvas start process over!');
    }

    checkHotUpdate() {
        hum.startProcess(null, true).subscribe({
            next: _ => {
                let eventCode = _.event.getEventCode();
                if (eventCode === native.EventAssetsManager.NEW_VERSION_FOUND) {
                    let am = _.event.getAssetsManagerEx();
                    let localVersion = am.getLocalManifest().getVersion();
                    let remoteVersion = am.getRemoteManifest().getVersion();
                    // 弹出提示框,让用户确认是否更新
                    DialogPanel.StartProcess(panel => {
                        let dialogPanel = panel as DialogPanel;
                        dialogPanel.content.value = `${i18n.t('lobby.dialogpanel.content_update')}\n${localVersion}->${remoteVersion}`;
                        dialogPanel.title.value = i18n.t('lobby.dialogpanel.title');
                        dialogPanel.okBtnText.value = i18n.t('lobby.dialogpanel.update');
                    }).subscribe(_ => {
                        if (_.result === 'ok') {
                            this.log('user confirm hotupdate');
                            // _.event.getAssetsManagerEx().update();
                            this.startHotUpdate();
                        } else {
                            this.log('user cancel hotupdate');
                            this.afterHotUpdate();
                        }
                    });
                } else if ([native.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST, native.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST, native.EventAssetsManager.ERROR_PARSE_MANIFEST].includes(eventCode)) {
                    lm.frontTipShow(`${HotUpdateManager.EventCodeToString(eventCode)}`).subscribe();
                }
            },
            complete: () => {
                this.log('hotupdate startProcess complete');
                this.afterHotUpdate();
            }
        });
    }

    startHotUpdate() {
        gm.loadingPanelMode = LoadingPanelMode.Default;
        gm.curProgressValue.value = 0;
        gm.curProgressValue2.value = 0;
        hum.startProcess(null).subscribe({
            next: _ => {
                if (_.event.getEventCode() === native.EventAssetsManager.UPDATE_PROGRESSION) {
                    if (_.event.getAssetsManagerEx().getState() == native.AssetsManager.State.UPDATING) {
                        // 注意此处必须包含这两个条件才能保证进度条的正确显示，只有UPDATE_PROGRESSION这个EventCode是不够的，它还包括两个manifest文件的下载
                        // 而在UPDATING下，就只有游戏资源的下载了
                        this.log('hotupdate update progression', _.event.getPercent(), _.event.getDownloadedBytes(), _.event.getTotalBytes());
                        this.curProgressValue = linear(0, 1, 0, 100, _.event.getPercent());
                        lm.hotupdateing.value = true;
                    }
                } else if (_.event.getEventCode() === native.EventAssetsManager.UPDATE_FINISHED) {
                    let am = _.event.getAssetsManagerEx();
                    var searchPathsSet = new Set(native.fileUtils.getSearchPaths());
                    var newSearchPaths = Array.from(new Set(am.getLocalManifest().getSearchPaths()));
                    newSearchPaths.forEach(_ => { searchPathsSet.delete(_) });
                    let searchPaths = Array.from(searchPathsSet);
                    searchPaths.unshift(...newSearchPaths); // 保证新的资源优先加载
                    localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
                    Timer(.5).subscribe(_ => {
                        game.restart();
                    });
                } else if ([native.EventAssetsManager.ERROR_UPDATING, native.EventAssetsManager.ERROR_UPDATING].includes(_.event.getEventCode())) {
                    lm.frontTipShow(`${HotUpdateManager.EventCodeToString(_.event.getEventCode())}`).subscribe();
                }
            },
            complete: () => {
                this.log('hotupdate startProcess complete');
                this.afterHotUpdate();
            }
        });
    }

    afterHotUpdate() {
        gm.curSubgame.value = GameKey.lobby;
        this.loadAudio();
    }

    // 加载音频
    loadAudio() {
        rm.loadRes([
            ['ab_lobby/Audio/bgm', ResType.AudioClipDir],
            ['ab_lobby/Audio/sfx', ResType.AudioClipDir],
        ]).subscribe({
            next: _ => {
                this.log('loadRes result', _);
            },
            complete: () => {
                am.genRootNode('ab_lobby').subscribe({
                    complete: () => {
                        am.bgm.again();
                    }
                });
                rm.finishedCount.value = 0; // 重置,否则会影响到下次进度条的初始位置
            }
        });
    }

    // 转TouchPosition到WorldPosition
    touchLocationToWorldPosition(location: Vec2, _out?: Vec3) {
        const result = this.camera.screenToWorld(v3(location.x, location.y, 0), _out ?? v3());
        _out.z = 0;
        result.z = 0;
        return result;
    }

}